<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="####1. WebSocket ######1). 背景B/S结构的软件项目中有时客户端需要实时的获得服务器消息，但默认HTTP协议只支持请求响应模式，这样做可以简化Web服务器，减少服务器的负担，加快响应速度，因为服务器不需要与客户端长时间建立一个通信链接，但不容易直接完成实时的消息推送功能，如聊天室、后台信息提示、实时更新数据等功能，但通过polling、Long polling、长连接、F">
<meta name="keywords" content="Android、iOS、Web、React Native">
<meta property="og:type" content="article">
<meta property="og:title" content="分布式---WebSocket-全双工通讯">
<meta property="og:url" content="http://yoursite.com/blog/2018/08/06/Distributed/分布式---WebSocket-全双工通讯/index.html">
<meta property="og:site_name" content="凌浩雨_博客">
<meta property="og:description" content="####1. WebSocket ######1). 背景B/S结构的软件项目中有时客户端需要实时的获得服务器消息，但默认HTTP协议只支持请求响应模式，这样做可以简化Web服务器，减少服务器的负担，加快响应速度，因为服务器不需要与客户端长时间建立一个通信链接，但不容易直接完成实时的消息推送功能，如聊天室、后台信息提示、实时更新数据等功能，但通过polling、Long polling、长连接、F">
<meta property="og:locale" content="default">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-2c1015b97d614b62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-0cd685861dc70b74.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-8bb03b59461b7536.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-09ceabcbfb38eb2e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-f513cbff4e51c287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-4ca1374d43292eb6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-7bd4931ecb432ced.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-08-06T11:07:39.322Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="分布式---WebSocket-全双工通讯">
<meta name="twitter:description" content="####1. WebSocket ######1). 背景B/S结构的软件项目中有时客户端需要实时的获得服务器消息，但默认HTTP协议只支持请求响应模式，这样做可以简化Web服务器，减少服务器的负担，加快响应速度，因为服务器不需要与客户端长时间建立一个通信链接，但不容易直接完成实时的消息推送功能，如聊天室、后台信息提示、实时更新数据等功能，但通过polling、Long polling、长连接、F">
<meta name="twitter:image" content="https://upload-images.jianshu.io/upload_images/3110861-2c1015b97d614b62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/blog/2018/08/06/Distributed/分布式---WebSocket-全双工通讯/"/>





  <title>分布式---WebSocket-全双工通讯 | 凌浩雨_博客</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">凌浩雨_博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/blog/blog/2018/08/06/Distributed/分布式---WebSocket-全双工通讯/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="凌浩雨">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpeg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="凌浩雨_博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">分布式---WebSocket-全双工通讯</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-08-06T18:01:38+08:00">
                2018-08-06
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>####1. <a href="http://www.websocket.org/" target="_blank" rel="noopener">WebSocket</a></p>
<p>######1). 背景<br>B/S结构的软件项目中有时客户端需要实时的获得服务器消息，但默认HTTP协议只支持请求响应模式，这样做可以简化Web服务器，减少服务器的负担，加快响应速度，因为服务器不需要与客户端长时间建立一个通信链接，但不容易直接完成实时的消息推送功能，如聊天室、后台信息提示、实时更新数据等功能，但通过polling、Long polling、长连接、Flash Socket以及HTML5中定义的WebSocket能完成该功能需要。</p>
<a id="more"></a>
<p>######2). OSI 模型与 TCP/IP<a href="http://www.colasoft.com.cn/download/protocols_map.php" target="_blank" rel="noopener">下载 pdf</a><br><img src="https://upload-images.jianshu.io/upload_images/3110861-2c1015b97d614b62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图1.png"></p>
<p>######3). Socket简介<br>Socket又称”套接字”，应用程序通常通过”套接字”向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”，作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。<br><img src="https://upload-images.jianshu.io/upload_images/3110861-0cd685861dc70b74.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图2.png"></p>
<p>I. Socket可以使用TCP/IP协议或UDP协议。<br>TCP/IP协议</p>
<ul>
<li>TCP/IP协议是目前应用最为广泛的协议，是构成Internet国际互联网协议的最为基础的协议,由TCP和IP协议组成:<br>=&gt; TCP协议:面向连接的、可靠的、基于字节流的传输层通信协议，负责数据的可靠性传输的问题。<br>=&gt; IP协议:用于报文交换网络的一种面向数据的协议，主要负责给每台网络设备一个网络地址，保证数据传输到正确的目的地。</li>
<li>UDP协议<br>UDP特点：无连接、不可靠、基于报文的传输层协议，优点是发送后不用管，速度比TCP快。</li>
</ul>
<p>II. B/S架构的系统多使用HTTP协议，HTTP协议的特点（底层通信使用Socket）：</p>
<ul>
<li>无状态协议</li>
<li>用于通过 Internet 发送请求消息和响应消息</li>
<li>使用端口接收和发送消息，默认为80端口<br><img src="https://upload-images.jianshu.io/upload_images/3110861-8bb03b59461b7536.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图3.png"></li>
</ul>
<p>######4).双向通信与消息推送</p>
<ul>
<li><strong>轮询</strong>：客户端定时向服务器发送Ajax请求，服务器接到请求后马上返回响应信息并关闭连接。<br>优点：后端程序编写比较容易。<br>缺点：请求中有大半是无用，浪费带宽和服务器资源。<br>实例：适于小型应用。</li>
<li><strong>长轮询</strong>：客户端向服务器发送Ajax请求，服务器接到请求后hold住连接，直到有新消息才返回响应信息并关闭连接，客户端处理完响应信息后再向服务器发送新的请求。<br>优点：在无消息的情况下不会频繁的请求，耗费资小。<br>缺点：服务器hold连接会消耗资源，返回数据顺序无保证，难于管理维护。 Comet异步的ashx，<br>实例：WebQQ、Hi网页版、Facebook IM。</li>
<li><strong>长连接</strong>：在页面里嵌入一个隐蔵iframe，将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求，服务器端就能源源不断地往客户端输入数据。<br>优点：消息即时到达，不发无用请求；管理起来也相对便。<br>缺点：服务器维护一个长连接会增加开销。<br>实例：Gmail聊天</li>
<li><strong>Flash Socket</strong>：在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信，JavaScript在收到服务器端传送的信息后控制页面的显示。<br>优点：实现真正的即时通信，而不是伪即时。<br>缺点：客户端必须安装Flash插件；非HTTP协议，无法自动穿越防火墙。<br>实例：网络互动游戏。</li>
<li><strong>Websocket</strong>: WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接，双向实时通信。<br>特点: 事件驱动、异步、使用ws或者wss协议的客户端socket、能够实现真正意义上的推送功能。<br>缺点：少部分浏览器不支持，浏览器支持的程度与方式有区别。</li>
</ul>
<p><img src="https://upload-images.jianshu.io/upload_images/3110861-09ceabcbfb38eb2e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图4.png"></p>
<p>####2. 示例</p>
<p>######1).  客户端<br>websocket允许通过JavaScript建立与远程服务器的连接，从而实现客户端与服务器间双向的通信。在websocket中有两个方法：　　<br>　　　　1、send() 向远程服务器发送数据<br>　　　　2、close() 关闭该websocket链接<br>　　websocket监听函数：<br>　　　　1、onopen 当网络连接建立时触发该事件<br>　　　　2、onerror 当网络发生错误时触发该事件<br>　　　　3、onclose 当websocket被关闭时触发该事件<br>　　　　4、onmessage 当websocket接收到服务器发来的消息的时触发的事件，也是通信中最重要的一个监听事件。msg.data<br>　　websocket还定义了一个readyState属性，这个属性可以返回websocket所处的状态：<br>　　　　1、CONNECTING(0) websocket正尝试与服务器建立连接<br>　　　　2、OPEN(1) websocket与服务器已经建立连接<br>　　　　3、CLOSING(2) websocket正在关闭与服务器的连接<br>　　　　4、CLOSED(3) websocket已经关闭了与服务器的连接<br>　　websocket的url开头是ws，如果需要ssl加密可以使用wss，当我们调用websocket的构造方法构建一个websocket对象（new WebSocket(url)）的之后，就可以进行即时通信了。</p>
<p>######2). 创建Web工程<br>I. 创建chat.html页面<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">	&lt;head&gt;</span><br><span class="line">		&lt;meta charset=&quot;UTF-8&quot;&gt;</span><br><span class="line">		&lt;title&gt;趣味聊天室&lt;/title&gt;</span><br><span class="line">		&lt;style type=&quot;text/css&quot;&gt;</span><br><span class="line">			/* 处理浏览器适配问题 */</span><br><span class="line">			* &#123;margin: 0;padding: 0;&#125;</span><br><span class="line">			a &#123;text-decoration: none;&#125;</span><br><span class="line">			body &#123;font-size: 14px;font-family: &quot;微软雅黑&quot;;&#125;</span><br><span class="line">			.wrap &#123;width: 700px; position: relative; top: 50px;left: calc(50% - 350px);display: flex;flex-direction:column;background: #F8F8F9;border-radius: 8px;user-select:none;-webkit-user-select:none;&#125;</span><br><span class="line">			</span><br><span class="line">			/* header start */</span><br><span class="line">			.wrap .header &#123;height: 80px;background: linear-gradient(200deg,#d6d1f1,#EE60E1);text-align: center;line-height: 80px;border-radius: 8px 8px 0 0;cursor: move;&#125;</span><br><span class="line">			.wrap .header span &#123;font-size: 28px;letter-spacing: 2px;color: #f1f1f1;&#125;</span><br><span class="line">			.wrap .header #close_btn &#123;position: absolute;right: 0px;top: 0px;width: 20px;height: 20px;background: url(img/close.png) no-repeat center;border-radius: 8px;&#125;</span><br><span class="line">			/* header end */</span><br><span class="line">			</span><br><span class="line">			/* main start */</span><br><span class="line">			.wrap .main &#123;display: flex;height: 300px;&#125;</span><br><span class="line">			</span><br><span class="line">			/* left start */</span><br><span class="line">			.wrap .left &#123;width: 260px;border-right: 1px solid #e1e1e1;&#125;</span><br><span class="line">			.wrap .time &#123;height: 30px;text-align: center;line-height: 30px;&#125;</span><br><span class="line">			.wrap .time .time_bg &#123;width: 20px;height: 20px;display: inline-block;vertical-align: middle;cursor: pointer;&#125;</span><br><span class="line">			.wrap .time span &#123;font-size: 14px;vertical-align: middle;color: #4EA9E9;cursor: pointer;&#125;</span><br><span class="line">			.wrap .left .left_people a&#123;height: 25px;text-align: center;line-height: 25px;margin-top: 3px;display: block;&#125;</span><br><span class="line">			/* left end */</span><br><span class="line">			</span><br><span class="line">			/* right start */</span><br><span class="line">			.wrap .right &#123;width: 700px;background: #f9f9f9;&#125;</span><br><span class="line">			.wrap .right .right_record &#123;height: 260px;padding-bottom: 10px;overflow: auto;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item &#123;width: 600px;margin: 0 auto;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item p &#123;text-align: center; font-size: 13px;color: #9A9797;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item .record_item_txt p &#123;text-align: left;margin: 5px 0 0 10px;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item .record_item_txt .avatar &#123;margin-left: 5px; color: #AC4BFD;font-size: 12px;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item .record_item_txt .txt &#123;color: #f1f1f1;&#125;</span><br><span class="line">			.wrap .right .right_record .record_item .record_item_txt p span &#123;border-radius: 10px; text-align: left;background: skyblue;padding: 3px 5px;font-size: 14px;color: #E833F6;&#125;</span><br><span class="line">			/* right end */</span><br><span class="line">			</span><br><span class="line">			/* content bottom start */</span><br><span class="line">			.wrap .content &#123;height: 140px;border-top: 1px solid #e1e1e1;display: flex;flex-direction:column;&#125;</span><br><span class="line">			.wrap .content .content_tool &#123;height: 30px;border-bottom: 1px solid #e1e1e1;display: flex;line-height: 41px;&#125;</span><br><span class="line">			.wrap .content .content_tool div &#123;margin-left: 20px;&#125;</span><br><span class="line">			.wrap .content .content_tool .bg &#123;width: 20px;height: 20px;display: inline-block;cursor: pointer;&#125;</span><br><span class="line">			</span><br><span class="line">			.wrap .content .content_text &#123;height: 90px;padding: 5px;outline: none;&#125;</span><br><span class="line">			.wrap .content .content_btn &#123;display: flex;justify-content:space-between;line-height: 30px;border-top: 1px solid #e1e1e1;&#125;</span><br><span class="line">			.wrap .content .content_btn .content_btn_text &#123;font-size: 12px;letter-spacing: 1px;line-height: 35px;color: #7E7D7D;margin-left: 10px;&#125;</span><br><span class="line">			.wrap .content .content_btn .btns &#123;width: 140px;display: flex;margin-top: 2px;&#125;</span><br><span class="line">			.wrap .content .btn_item &#123;width: 80px;height: 25px;text-align: center;line-height: 25px;border: 1px solid #c1c1c1;color: #313333;cursor: pointer;margin-right: 5px;letter-spacing: 1px;border-radius: 4px;&#125;</span><br><span class="line">			/* content bottom end */			</span><br><span class="line">		&lt;/style&gt;</span><br><span class="line">	&lt;/head&gt;</span><br><span class="line">	&lt;body&gt;</span><br><span class="line">		&lt;!-- &lt;canvas id=&quot;dot&quot;&gt;&lt;/canvas&gt; --&gt;</span><br><span class="line">		&lt;div class=&quot;wrap&quot;&gt;</span><br><span class="line">			&lt;div class=&quot;header&quot;&gt;</span><br><span class="line">				&lt;span&gt;趣味聊天室&lt;/span&gt;</span><br><span class="line">				&lt;a href=&quot;javascript:void(0)&quot; id=&quot;close_btn&quot;&gt;&lt;/a&gt;</span><br><span class="line">			&lt;/div&gt;</span><br><span class="line">			&lt;div class=&quot;main&quot;&gt;</span><br><span class="line">				&lt;!-- left --&gt;</span><br><span class="line">				&lt;!-- right --&gt;</span><br><span class="line">				&lt;div class=&quot;right&quot;&gt;</span><br><span class="line">					&lt;div class=&quot;time&quot;&gt;</span><br><span class="line">						&lt;i class=&quot;time_bg&quot; style=&quot;background: url(img/clock.png) no-repeat;&quot;&gt;&lt;/i&gt;</span><br><span class="line">						&lt;span&gt;聊天记录&lt;/span&gt;</span><br><span class="line">					&lt;/div&gt;</span><br><span class="line">					&lt;!-- 聊天记录 --&gt;</span><br><span class="line">					&lt;div class=&quot;right_record&quot; id=&quot;outputMessage&quot;&gt;&lt;/div&gt;</span><br><span class="line">				&lt;/div&gt;</span><br><span class="line">			&lt;/div&gt;</span><br><span class="line">			</span><br><span class="line">			&lt;!-- content tool/txt --&gt;</span><br><span class="line">			&lt;div class=&quot;content&quot;&gt;</span><br><span class="line">				&lt;div class=&quot;content_tool&quot;&gt;</span><br><span class="line">					&lt;div class=&quot;tool_font&quot;&gt;</span><br><span class="line">						&lt;i class=&quot;bg&quot; style=&quot;background: url(img/font.png) no-repeat;&quot;&gt;&lt;/i&gt;</span><br><span class="line">					&lt;/div&gt;</span><br><span class="line">					&lt;div class=&quot;tool_emjo&quot;&gt;</span><br><span class="line">						&lt;i class=&quot;bg&quot; style=&quot;background: url(img/emjo.png) no-repeat;&quot;&gt;&lt;/i&gt;</span><br><span class="line">					&lt;/div&gt;</span><br><span class="line">				&lt;/div&gt;</span><br><span class="line">				</span><br><span class="line">				&lt;div class=&quot;content_text&quot; contenteditable=&quot;true&quot; id=&quot;inputMessage&quot;&gt;&lt;/div&gt;</span><br><span class="line">				</span><br><span class="line">				&lt;div class=&quot;content_btn&quot;&gt;</span><br><span class="line">					&lt;div class=&quot;content_btn_text&quot;&gt;&lt;i&gt;自己的DIY聊天室&lt;/i&gt;&lt;/div&gt;</span><br><span class="line">					&lt;div class=&quot;btns&quot;&gt;</span><br><span class="line">						&lt;div class=&quot;send btn_item&quot; onclick=&quot;getMessage();&quot;&gt;</span><br><span class="line">							&lt;span&gt;发送&lt;/span&gt;&lt;span&gt;(S)&lt;/span&gt;</span><br><span class="line">						&lt;/div&gt;</span><br><span class="line">						&lt;div class=&quot;close btn_item&quot;&gt;</span><br><span class="line">							&lt;span&gt;关闭&lt;/span&gt;&lt;span&gt;(C)&lt;/span&gt;</span><br><span class="line">						&lt;/div&gt;</span><br><span class="line">					&lt;/div&gt;</span><br><span class="line">				&lt;/div&gt;</span><br><span class="line">			&lt;/div&gt;</span><br><span class="line">		&lt;/div&gt;</span><br><span class="line">		</span><br><span class="line">		&lt;!-- 引入jQuery --&gt;</span><br><span class="line">    	&lt;!-- &lt;script src=&quot;http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js&quot;&gt;&lt;/script&gt; --&gt;</span><br><span class="line">    	&lt;script type=&quot;text/javascript&quot;&gt;</span><br><span class="line">    		// 定义服务器地址和请求类型</span><br><span class="line">    		var wsUrl = &quot;ws://localhost:8080/WebSocketTest/chatServer&quot;;</span><br><span class="line">    		// 客户端与服务建立连接，连接成功后，发出ws.onopen事件</span><br><span class="line">    		var ws = new WebSocket(wsUrl);</span><br><span class="line">    		/** </span><br><span class="line">    		* 连接成功后，提示浏览器客户端输入昵称 </span><br><span class="line">    		*/</span><br><span class="line">    		ws.onopen = function() &#123;</span><br><span class="line">				var userName = prompt(&quot;请给自己取一个名字：&quot;);</span><br><span class="line">				// 发送用户名</span><br><span class="line">				ws.send(userName);</span><br><span class="line">			&#125;</span><br><span class="line">    		</span><br><span class="line">    		/**</span><br><span class="line">    		* 客户端收到服务器发送的消息</span><br><span class="line">    		*/</span><br><span class="line">    		ws.onmessage = function(message) &#123;</span><br><span class="line">				// 获取以后，在客户端显示</span><br><span class="line">				outputMessage.innerHTML = outputMessage.innerHTML + message.data;</span><br><span class="line">				// 获取outputMessage盒子</span><br><span class="line">				var msg = document.getElementById(&quot;outputMessage&quot;);</span><br><span class="line">				// 差值，溢出的高度 - 可视的高度</span><br><span class="line">				var distance = msg.scrollHeight - msg.offsetHeight;</span><br><span class="line">				// 将差值赋值给滚动条的高度</span><br><span class="line">				msg.scrollTop = distance;</span><br><span class="line">			&#125;</span><br><span class="line">    		</span><br><span class="line">    		/**</span><br><span class="line">    		* 获取某个用户输入的聊天内容，并发送给服务端，让服务端广播给所有人</span><br><span class="line">    		*/</span><br><span class="line">    		function getMessage() &#123;</span><br><span class="line">    			// 获取输入框信息</span><br><span class="line">				var inputMessage = document.getElementById(&quot;inputMessage&quot;).innerText;</span><br><span class="line">    			// 判断内容是否为空</span><br><span class="line">    			if (typeof(inputMessage) == &quot;undefined&quot;) &#123;</span><br><span class="line">					alert(&quot;请输入您要发送的信息&quot;);</span><br><span class="line">				&#125; else &#123;</span><br><span class="line">					// 获取到输入的消息，发送给服务端，并广播给所有用户</span><br><span class="line">					ws.send(inputMessage);</span><br><span class="line">					document.getElementById(&quot;inputMessage&quot;).innerText = &quot;&quot;;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">    		</span><br><span class="line">    		/**</span><br><span class="line">    		* 当关闭页面的时候，或者用户退出的时候，会执行ws.close()方法</span><br><span class="line">    		*/</span><br><span class="line">    		window.onbeforeunload = function() &#123;</span><br><span class="line">				ws.close();</span><br><span class="line">			&#125;</span><br><span class="line">    		</span><br><span class="line">    		/**</span><br><span class="line">    		* 回车键发送消息</span><br><span class="line">    		*/</span><br><span class="line">    		document.onkeyup = function(e) &#123;</span><br><span class="line">				if (e.keyCode == 13) &#123;</span><br><span class="line">					getMessage();</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">    		</span><br><span class="line">    	&lt;/script&gt;</span><br><span class="line">	&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure></p>
<p>II. 图片资源<br><img src="https://upload-images.jianshu.io/upload_images/3110861-f513cbff4e51c287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图5.png"></p>
<p>III. 目录结构<br><img src="https://upload-images.jianshu.io/upload_images/3110861-4ca1374d43292eb6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图6.png"></p>
<p>######3). 服务器ChatServer代码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 趣味聊天的服务端程序</span><br><span class="line"> * </span><br><span class="line"> * @author mazaiting</span><br><span class="line"> */</span><br><span class="line">// 声明WebSocket服务器的地址</span><br><span class="line">@ServerEndpoint(&quot;/chatServer&quot;)</span><br><span class="line">public class ChatServer &#123;</span><br><span class="line">	/** 是否是第一次进入 */</span><br><span class="line">	private boolean isFirstFlag = true;</span><br><span class="line">	private Session session;</span><br><span class="line">	/** 用户名 */</span><br><span class="line">	private String userName;</span><br><span class="line">	/**</span><br><span class="line">	 * 记录此次聊天室的服务端有多少个连接 key代表此次客户端的Session ID，value代表此次连接对象</span><br><span class="line">	 */</span><br><span class="line">	private static final HashMap&lt;String, Object&gt; connectMap = new HashMap&lt;&gt;();</span><br><span class="line">	/**</span><br><span class="line">	 * 保存所有用户的昵称信息 key是Session ID，value才是用户名</span><br><span class="line">	 */</span><br><span class="line">	private static final HashMap&lt;String, String&gt; userMap = new HashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">	/**</span><br><span class="line">	 * 服务端收到客户端连接请求，连接成功后会执行此方法</span><br><span class="line">	 * </span><br><span class="line">	 * @param session</span><br><span class="line">	 */</span><br><span class="line">	@OnOpen</span><br><span class="line">	public void start(Session session) &#123;</span><br><span class="line">		this.session = session;</span><br><span class="line">		connectMap.put(session.toString(), this);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	/**</span><br><span class="line">	 * 发送消息</span><br><span class="line">	 * </span><br><span class="line">	 * @param clientMessage</span><br><span class="line">	 *            消息/用户名</span><br><span class="line">	 * @param session</span><br><span class="line">	 *            会话</span><br><span class="line">	 */</span><br><span class="line">	@OnMessage</span><br><span class="line">	public void chat(String clientMessage, Session session) &#123;</span><br><span class="line">		// 消息</span><br><span class="line">		String message;</span><br><span class="line">		// 判断是否为第一次发送消息</span><br><span class="line">		if (isFirstFlag) &#123;</span><br><span class="line">			// 用户名赋值</span><br><span class="line">			this.userName = clientMessage;</span><br><span class="line">			// 将新进来的用户保存到用户map</span><br><span class="line">			userMap.put(session.getId(), userName);</span><br><span class="line">			// 构造发送给客户端的提示信息</span><br><span class="line">			message = htmlMessage(&quot;系统消息&quot;, userName + &quot;进入聊天室&quot;);</span><br><span class="line">			// 输入昵称后，代表isFirstFlag=false</span><br><span class="line">			isFirstFlag = false;</span><br><span class="line">		&#125; else &#123;</span><br><span class="line">			// 构造发送给客户端的提示信息</span><br><span class="line">			message = htmlMessage(userMap.get(session.getId()), clientMessage);</span><br><span class="line">		&#125;</span><br><span class="line">		sendMessageForAll(message);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	/**</span><br><span class="line">	 * ws.close()方法调用后，会触发后台的标注OnClose方法</span><br><span class="line">	 * </span><br><span class="line">	 * @param session</span><br><span class="line">	 */</span><br><span class="line">	@OnClose</span><br><span class="line">	public void close(Session session) &#123;</span><br><span class="line">		// 当某个用户退出时，对其他用户进行广播</span><br><span class="line">		String message = htmlMessage(&quot;系统消息&quot;, userMap.get(session.getId()) + &quot;退出了聊天室&quot;);</span><br><span class="line">		// 用户map移除</span><br><span class="line">		userMap.remove(session.getId());</span><br><span class="line">		// 链接map移除</span><br><span class="line">		connectMap.remove(session.getId());</span><br><span class="line">		sendMessageForAll(message);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	/**</span><br><span class="line">	 * 格式化消息</span><br><span class="line">	 * @param userName 用戶名</span><br><span class="line">	 * @param message 消息</span><br><span class="line">	 * @return 消息</span><br><span class="line">	 */</span><br><span class="line">	private String htmlMessage(String userName, String message) &#123;</span><br><span class="line">		StringBuffer messageBuffer = new StringBuffer();</span><br><span class="line">		SimpleDateFormat sFormat = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;div class=&apos;record_item&apos;&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;p class=&apos;record_item_time&apos;&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;span&gt;&quot; + sFormat.format(new Date()) + &quot;&lt;/span&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;/p&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;div class=&apos;record_item_txt&apos;&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;span class=&apos;avatar&apos;&gt;&quot; + userName + &quot;&lt;/span&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;p&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;span class=&apos;txt&apos;&gt;&quot; + message + &quot;&lt;/span&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;/p&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;/div&gt;&quot;);</span><br><span class="line">		messageBuffer.append(&quot;&lt;/div&gt;&quot;);</span><br><span class="line">		return messageBuffer.toString();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	/**</span><br><span class="line">	 * 为所有用户发送消息</span><br><span class="line">	 * </span><br><span class="line">	 * @param message</span><br><span class="line">	 *            消息</span><br><span class="line">	 */</span><br><span class="line">	private void sendMessageForAll(String message) &#123;</span><br><span class="line">		// 当前对象</span><br><span class="line">		ChatServer client = null;</span><br><span class="line">		// 将消息广播给所有人</span><br><span class="line">		for (String connectKey : connectMap.keySet()) &#123;</span><br><span class="line">			// 获取客户端</span><br><span class="line">			client = (ChatServer) connectMap.get(connectKey);</span><br><span class="line">			// 给对应的web端发送一个文本信息</span><br><span class="line">			try &#123;</span><br><span class="line">				client.session.getBasicRemote().sendText(message);</span><br><span class="line">			&#125; catch (IOException e) &#123;</span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">			;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######4). 服务端注解</p>
<ul>
<li>@ServerEndpoint: 绑定服务器地址的注解方法</li>
<li>@OnOpen: WebSocket连接执行的注解方法</li>
<li>@OnMessage: 发送消息时执行的方法</li>
<li>@OnClose: 关闭时执行的方法</li>
</ul>
<p>######5). 测试<br><img src="https://upload-images.jianshu.io/upload_images/3110861-7bd4931ecb432ced.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图7.png"></p>
<p>####3. 开源框架</p>
<p>######1). 开源Java消息推送框架 <a href="https://github.com/wjw465150/Pushlet" target="_blank" rel="noopener">Pushlet</a><br>Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。<br>Pushlet是一种comet实现：在Servlet机制下，数据从server端的Java对象直接推送（push）到（动态）HTML页面，而无需任何Javaapplet或者插件的帮助。它使server端可以周期性地更新client的web页面，这与传统的request/response方式相悖。浏览器client为兼容JavaScript1.4版本以上的浏览器（如InternetExplorer、FireFox），并使用JavaScript/DynamicHTML特性。而底层实现使用一个servlet通过Http连接到JavaScript所在的浏览器，并将数据推送到后者。</p>
<p>####<a href="https://gitee.com/mazaiting/distributed" target="_blank" rel="noopener">代码下载</a></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/08/06/Android-Special-Function/Android-逆向(反编译)/" rel="next" title="Android-逆向(反编译)">
                <i class="fa fa-chevron-left"></i> Android-逆向(反编译)
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/08/06/Distributed/分布式--ActiveMQ-消息中间件(一)/" rel="prev" title="分布式--ActiveMQ-消息中间件(一)">
                分布式--ActiveMQ-消息中间件(一) <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/blog/images/avatar.jpeg"
                alt="凌浩雨" />
            
              <p class="site-author-name" itemprop="name">凌浩雨</p>
              <p class="site-description motion-element" itemprop="description">专业从事于移动端开发，Android与iOS均有涉及，主做Android开发与React Native开发</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">393</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">凌浩雨</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
